package org.liveboardgames.agricola.control.delegates.mock
{
	import mx.collections.ListCollectionView;
	
	import org.liveboardgames.agricola.model.enums.ActionOutputEnum;
	import org.liveboardgames.agricola.model.enums.ActionTempoEnum;
	import org.liveboardgames.agricola.model.enums.HouseTypeEnum;
	import org.liveboardgames.agricola.model.enums.PrerequisiteEnum;
	import org.liveboardgames.agricola.model.enums.ResourceTypeEnum;
	import org.liveboardgames.agricola.model.enums.RoundOffsetTypeEnum;
	import org.liveboardgames.agricola.vo.action.Action;
	import org.liveboardgames.agricola.vo.action.ResourceTransformationAction;
	import org.liveboardgames.agricola.vo.action.ResourcesOnBoardAction;
	import org.liveboardgames.agricola.vo.common.Target;
	import org.liveboardgames.common.dictionary.collections.HashCollection;
	import org.liveboardgames.common.dictionary.collections.IMap;

	public class ActionFactory
	{
		public static const RESOURCE_TYPE:String = "resourceType";

		public static const QUANTITY:String = "quantity";

		public static const ROUNDS:String = "rounds";

		public static const OFFSET_TYPE:String = "offsetType";

		public static function getResourceAction(resourceType:String, quantity:int, isCumulative:Boolean = false):Action
		{
			var action:Action = new Action();
			action.name = "Resource action: " + resourceType;

			action.actionOutput = resourceType;
			action.outputQuantity = quantity;

			if (isCumulative)
			{
				action.tempo = ActionTempoEnum.START_OF_ROUND;
			}
			else
			{
				action.tempo = ActionTempoEnum.PEEP_TRIGGERED;
			}
			return action;
		}

		public static function getTakeAllAction(target:Target):Action
		{
			var action:Action = new Action();
			action.name = "Take all";
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;
			action.link = target;

			action.actionOutput = ActionOutputEnum.TAKE_ALL;

			action.needPlayerInput = false;

			return action;
		}

		/**
		 * Three different actions at the same time (one
		 * for each material), and it will be the action
		 * processor's job to filter out the ones that are not
		 * available.
		 */
		public static function getRoomAction(material:String):Action
		{
			var action:Action = new Action();
			action.name = "Room " + material;
			// Can use the action any number of times
			// TODO: check whether it is really useful to have 
			// an attribute for this, and whether it is not possible 
			// to use the integer in the output
			action.numberOfUses = 0;

			// The kind of room you will get with the action
			var actionOutput:String = null;
			// The material needed to build it (does not include 
			// reed, that is common to all three of them)
			var resourceTypeCost:String = null;
			// The prerequisite that the processor will need to 
			// check before allowing this action
			var prerequisite:String = null;
			if (HouseTypeEnum.WOODEN == material)
			{
				actionOutput = ActionOutputEnum.WOODEN_ROOM;
				resourceTypeCost = ResourceTypeEnum.WOOD;
				prerequisite = PrerequisiteEnum.WOODEN_HOUSE;
			}
			else if (HouseTypeEnum.CLAY == material)
			{
				actionOutput = ActionOutputEnum.CLAY_ROOM;
				resourceTypeCost = ResourceTypeEnum.CLAY;
				prerequisite = PrerequisiteEnum.CLAY_HOUSE;
			}
			else if (HouseTypeEnum.STONE == material)
			{
				actionOutput = ActionOutputEnum.STONE_ROOM;
				resourceTypeCost = ResourceTypeEnum.STONE;
				prerequisite = PrerequisiteEnum.STONE_HOUSE;
			}
			// For each use of the action, get one room
			action.actionOutput = actionOutput;
			// The action is one that is triggered by the placement 
			// of a peep
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;

			// Set the prerequisite that needs to be satisfied before 
			// being able to accomplish that action
			action.addPrerequisite(prerequisite);
			action.addPrerequisite(PrerequisiteEnum.EMPTY_SPACE);

			// Cost depends on the material
			var cost:IMap = new HashCollection();
			cost.put(resourceTypeCost, 5);
			cost.put(ResourceTypeEnum.REED, 2);
			action.cost = cost;

			action.needPlayerInput = true;

			return action;
		}

		public static function getStableAction(woodCost:int, numberOfUses:int = 1):Action
		{
			var action:Action = new Action();
			action.name = "Stable";
			var cost:IMap = new HashCollection();
			cost.put(ResourceTypeEnum.WOOD, woodCost);
			action.cost = cost;

			action.actionOutput = ActionOutputEnum.STABLE;

			action.numberOfUses = numberOfUses;
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;
			action.addPrerequisite(PrerequisiteEnum.AVAILABLE_STABLE);
			action.needPlayerInput = true;

			return action;
		}

		public static function getFirstPlayerAction():Action
		{
			var action:Action = new Action();
			action.name = "First player";
			action.actionOutput = ActionOutputEnum.FIRST_PLAYER;
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;
			action.needPlayerInput = false;
			return action;
		}

		public static function getPloughAction():Action
		{
			var action:Action = new Action();
			action.name = "Plough";
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;

			action.actionOutput = ActionOutputEnum.PLOUGH;

			action.addPrerequisite(PrerequisiteEnum.EMPTY_SPACE);
			return action;
		}

		public static function getBakeAction():Action
		{
			var action:Action = new Action();
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;
			action.name = "Bake";

			// The minimum cost to bake is one grain
			var cost:IMap = new HashCollection();
			cost.put(ResourceTypeEnum.GRAIN, 1);
			action.cost = cost;

			action.actionOutput = ActionOutputEnum.BAKE;

			// Prerequisite: grain to bake + oven
			action.addPrerequisite(PrerequisiteEnum.OVEN);
			return action;
		}

		public static function getSowAction():Action
		{
			var action:Action = new Action();
			action.name = "Sow";
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;

			action.actionOutput = ActionOutputEnum.SOW;

			// Prerequisite: field to plough
			action.addPrerequisite(PrerequisiteEnum.FREE_FIELD);

			return action;
		}

		public static function getFencesAction():Action
		{
			var action:Action = new Action();
			action.name = "Fences";
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;

			action.actionOutput = ActionOutputEnum.PASTURE;

			// Add prerequisite to be able to build at least one pasture
			// This means that there are enough fences left to build the small possible pasture
			action.addPrerequisite(PrerequisiteEnum.CAN_BUILD_PASTURE);

			return action;
		}

		public static function getMajorImprovementAction():Action
		{
			var action:Action = new Action();
			action.name = "Major Improvement";
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;

			action.actionOutput = ActionOutputEnum.MAJOR_IMPROVEMENT;

			// The player needs to be able to build one major improvement to use the action
			action.addPrerequisite(PrerequisiteEnum.BUILD_MAJOR_IMPROVEMENT);

			return action;
		}

		/**
		 * Two different actions at the same time (one
		 * for wood to clay, and one for clay to stone), and it will be the action
		 * processor's job to filter out the ones that are not
		 * available.
		 *
		 * @param material The material to which to renovate
		 */
		public static function getRenovationAction(material:String):Action
		{
			var action:Action = new Action();
			action.name = "Renovation " + material;

			var output:IMap = new HashCollection();
			// The kind of room you will get with the action
			var actionOutput:String = null;
			// The material needed to build it (does not include 
			// reed, that is common to all three of them)
			var resourceTypeCost:String = null;
			// The prerequisite that the processor will need to 
			// check before allowing this action
			var prerequisite:String = null;
			if (HouseTypeEnum.CLAY == material)
			{
				actionOutput = ActionOutputEnum.RENOVATION_TO_CLAY;
				resourceTypeCost = ResourceTypeEnum.CLAY;
				prerequisite = PrerequisiteEnum.WOODEN_HOUSE;
			}
			else if (HouseTypeEnum.STONE == material)
			{
				actionOutput = ActionOutputEnum.RENOVATION_TO_STONE;
				resourceTypeCost = ResourceTypeEnum.STONE;
				prerequisite = PrerequisiteEnum.CLAY_HOUSE;
			}
			// For each use of the action, get one room
			action.actionOutput = actionOutput;

			// The action is one that is triggered by the placement 
			// of a peep
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;

			// Set the prerequisite that needs to be satisfied before 
			// being able to accomplish that action
			action.addPrerequisite(prerequisite);

			// Cost depends on the material
			var cost:IMap = new HashCollection();
			cost.put(resourceTypeCost, 0);
			cost.put(ResourceTypeEnum.REED, 1);
			action.cost = cost;

			return action;
		}

		public static function getTakeAnimalAction(target:Target):Action
		{
			var action:Action = new Action();
			action.name = "Take animal";
			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;
			action.link = target;

			action.actionOutput = ActionOutputEnum.TAKE_ANIMAL

			return action;
		}

		public static function getBirthAction():Action
		{
			var action:Action = getBirthWithoutRoomAction();
			action.name = "Birth";
			action.addPrerequisite(PrerequisiteEnum.EMPTY_ROOM);

			return action;
		}

		public static function getBirthWithoutRoomAction():Action
		{
			var action:Action = new Action();
			action.name = "Birth without room";

			action.actionOutput = ActionOutputEnum.BIRTH;

			action.tempo = ActionTempoEnum.PEEP_TRIGGERED;

			action.addPrerequisite(PrerequisiteEnum.AVAILABLE_PEEP);

			return action;
		}

		public static function getCookingAction(sheep:int, boar:int, cattle:int, vegetable:int, grain:int):ResourceTransformationAction
		{
			var possibleTransformations:ListCollectionView = ResourceTransformationFactory.getPossibleTransformationsForCooking(sheep,
				boar, cattle, vegetable, grain);
			var action:ResourceTransformationAction = ActionFactory.getResourceTransformationAction(possibleTransformations);
			action.addPrerequisite(PrerequisiteEnum.COOKING_PLACE);

			return action;
		}

		public static function getBakingAction(grain:int, numberOfUses:int):ResourceTransformationAction
		{
			var possibleTransformations:ListCollectionView = ResourceTransformationFactory.getPossibleTransformationsForBaking(grain,
				numberOfUses);
			var action:ResourceTransformationAction = ActionFactory.getResourceTransformationAction(possibleTransformations);
			action.addPrerequisite(PrerequisiteEnum.OVEN);

			return action;
		}

		public static function getAddResourceOnBoardAction(resource:String, roundNumbers:ListCollectionView, roundOffsetType:String,
			quantity:int):Action
		{
			var action:ResourcesOnBoardAction = new ResourcesOnBoardAction();
			action.name = "Add resources on board";
			action.needPlayerInput = false;

			action.actionOutput = ActionOutputEnum.ADD_RESOURCE_ON_BOARD;

			action.resourceType = resource;
			action.rounds = roundNumbers;
			action.quantity = quantity;
			action.offsetType = roundOffsetType;

			return action;
		}

		public static function getTakeResourceOnBoardAction(resource:String, roundNumbers:ListCollectionView, roundOffsetType:String,
			quantity:int):Action
		{
			var action:ResourcesOnBoardAction = new ResourcesOnBoardAction();
			action.name = "Take resources from board";
			action.needPlayerInput = false;

			action.actionOutput = ActionOutputEnum.TAKE_RESOURCE_FROM_BOARD;

			action.resourceType = resource;
			action.rounds = roundNumbers;
			action.quantity = quantity;
			action.offsetType = roundOffsetType;

			action.tempo = ActionTempoEnum.START_OF_ROUND;
			// TODO: target?

			return action;
		}

		public static function getResourceTransformationAction(resourceTransformations:ListCollectionView):ResourceTransformationAction
		{
			var action:ResourceTransformationAction = new ResourceTransformationAction();
			action.name = "Resource transformation";

			action.possibleTransformations = resourceTransformations;

			action.actionOutput = ActionOutputEnum.RESOURCE_TRANSFORMATION;

			return action;
		}
	}
}